/*
 * Copyright (c) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

#include "hi_ext_util.h"
#include "evt_mon.h"

#define EPOLL_RES_EVTS_MAX      10 // epoll的result buf size

/**
    Event handler info.
*/
typedef struct EvtProc {
    struct list_head lnode; // 作为链表节点
    EmEvtProc proc; // 事件处理函数
    void *user; // 事件处理user
    int fd; // 待监视的fd
}   EvtProc;

/**
    Event Monitor数据成员.
*/
struct EvtMon {
    struct list_head procList; // 存储所有add的EvtProc

    int epollFd; // epoll fd
    int abortFd; // 监听quit事件的fd, 用eventfd()创建
    int usrFdNum; // 监听的usr fd的数量，退出时应为0，可用于退出时错误检测

    // 由于user在事件处理过程中可能会删除之前注册的fd，需要做相应处理
#   ifndef __HuaweiLite__
    struct epoll_event waitResEvts[EPOLL_RES_EVTS_MAX]; // 用于epoll_wait返回结果evts的数组
#   endif
    int waitResNum; // 当前epoll_wait返回的结果evts的数量

    pthread_t svcThrdId; // 后台线程ID，在APP通过emon_start()启动服务时使用
    pthread_t wdThrdId; // watchdog线程ID
    int wdAbortFd; // watchdog abort fd，watchdog线程用其查看quit事件
    int wdCancelFd; // watchdog cancel fd，用于指示当前wd取消
};

/**
    Event check return.
*/
void EvtChkRet(uint32_t detectedEvts, uint32_t monitoredEvt, int fd)
{
    if ((detectedEvts) & ~(monitoredEvt)) {
        LOGE("detect un-mon evts, fd=%d, devts=%x, mevt=%x\n", (fd), (detectedEvts), (monitoredEvt));
    }
    if (!((detectedEvts) & (monitoredEvt))) {
        LOGW("detect invalid evts, fd=%d, devts=%x, mevt=%x\n", (fd), (detectedEvts), (monitoredEvt));
        return;
    }
}

/**
    create EmEvtProc.
*/
static EvtProc* EvtProcNew(int fd, EmEvtProc proc, void* user)
{
    EvtProc *self;

    self = (EvtProc*)malloc(sizeof(*self));
    if (!self) {
        HI_ASSERT(0);
    }
    INIT_LIST_HEAD(&self->lnode);
    self->proc = proc;
    self->user = user;
    self->fd = fd;
    return self;
}

/**
    创建EvtMon.
*/
int EmCreate(EvtMon** emon)
{
    HI_ASSERT(emon);
    EvtMon *self;

    self = (EvtMon*)malloc(sizeof(*self));
    HI_ASSERT(self);
    *emon = self;

    /* init struct parameters */
    INIT_LIST_HEAD(&self->procList);
#   ifndef __HuaweiLite__
    self->epollFd = epoll_create1(EPOLL_CLOEXEC);
    HI_ASSERT(self->epollFd >= 0);
#   else
    self->epollFd = -1;
#   endif
    self->abortFd = EventFdCreate();
    HI_ASSERT(self->abortFd >= 0);
    self->usrFdNum = 0;
    self->svcThrdId = pthread_self(); // 在run()时会被重置
    self->wdThrdId = 0;
    self->wdAbortFd = 0;
    self->wdCancelFd = 0;
    return 0;
}

/**
    销毁EvtMon.
*/
void EmDestroy(EvtMon* self)
{
    HI_ASSERT(self);

    if (self->abortFd >= 0) {
        close(self->abortFd);
    }
    if (self->epollFd >= 0) {
        close(self->epollFd);
    }

    struct list_head *node = NULL;
    struct list_head *next = NULL;
    list_for_each_safe(node, next, &self->procList) {
        EvtProc *proc = list_entry(node, EvtProc, lnode);
        free(proc);
    }
    free(self);
}

static EvtProc* EmFindFd(EvtMon* self, int fd)
{
    struct list_head *node = NULL;
    struct list_head *next = NULL;

    list_for_each_safe(node, next, &self->procList) {
        EvtProc *proc = list_entry(node, EvtProc, lnode);
        if (proc->fd == fd) {
            return proc;
        }
    }
    return NULL;
}

/**
    获得关联的服务线程的ID.
*/
pthread_t EmThrdId(EvtMon* self)
{
    HI_ASSERT(self);
    return self->svcThrdId;
}

#ifndef __HuaweiLite__

/**
    添加fd以监听.
*/
int EmAddFd(EvtMon* self, int fd, int evts, EmEvtProc cb, void* user)
{
    HI_ASSERT(self);
    EvtProc *proc = NULL;
    struct epoll_event ev;
    int err;

    proc = EvtProcNew(fd, cb, user);
    if (memset_s(&ev, sizeof(ev), 0, sizeof(ev)) != EOK) {
        HI_ASSERT(0);
    }
    ev.events = evts;
    ev.data.ptr = proc;

    err = epoll_ctl(self->epollFd, EPOLL_CTL_ADD, fd, &ev);
    if (err < 0) {
        LOGE("epoll_ctl for add FAIL, err='%s'\n", strerror(errno));
        free(proc);
        return err;
    }

    list_add_tail(&proc->lnode, &self->procList);
    self->usrFdNum++;
    return 0;
}

/**
    删除对指定fd的所有监听.
*/
int EmDelFd(EvtMon* self, int fd)
{
    HI_ASSERT(self && fd >= 0);
    EvtProc *proc = NULL;
    int err;

    proc = EmFindFd(self, fd);
    if (!proc) {
        LOGE("del fd FAIL, for fd(%d) not found\n", fd);
        return -1;
    }

    // 从当前结果列表中查找并做标记
    for (int n = 0; n < self->waitResNum; n++) {
        // abortEvt也应该用EvtProc结构
        if (self->waitResEvts[n].data.fd == self->abortFd) {
            continue;
        }

        EvtProc *proc = (EvtProc*)self->waitResEvts[n].data.ptr;
        if (!proc) {
            continue;
        }
        if (proc->fd == fd) {
            self->waitResEvts[n].data.ptr = NULL;
        }
    }

    err = epoll_ctl(self->epollFd, EPOLL_CTL_DEL, fd, NULL);
    if (err < 0) {
        LOGE("epoll_ctl for del FAIL, err='%s'\n", strerror(errno));
    }

    // 即便epoll_ctl失败，也要free该节点
    list_del(&proc->lnode);
    self->usrFdNum--;
    HI_ASSERT(self->usrFdNum >= 0);
    free(proc);
    return err < 0 ? err : 0;
}

/**
    修改监听事件类型.
*/
int EmModFd(EvtMon* self, int fd, int evts)
{
    HI_ASSERT(0);
    return -1;
}

/**
    进入监听循环.
*/
int EmRun(EvtMon* self)
{
    HI_ASSERT(self);
    struct epoll_event abortEv;
    int n;
    int nfds;
    int err;

    self->svcThrdId = pthread_self();

    if (memset_s(&abortEv, sizeof(abortEv), 0, sizeof(abortEv)) != EOK) {
        HI_ASSERT(0);
    }
    abortEv.events = FDE_IN;
    abortEv.data.fd = self->abortFd;
    // add abort event to epoll
    err = epoll_ctl(self->epollFd, EPOLL_CTL_ADD, self->abortFd, &abortEv);
    if (err < 0) {
        return err;
    }

    // 退出处理，需要从epoll中del abortEvt，等
    while (1) {
        self->waitResNum = 0;
        if (memset_s(self->waitResEvts, sizeof(self->waitResEvts), 0, sizeof(self->waitResEvts)) != EOK) {
            HI_ASSERT(0);
        }
        nfds = epoll_wait(self->epollFd, self->waitResEvts, EPOLL_RES_EVTS_MAX, -1);
        if (nfds < 0) {
            continue;
        }
        self->waitResNum = nfds;

        for (n = 0; n < nfds; n++) {
            // abortEvt也应该用EvtProc结构
            // receive quit event ,exit event monitor immediately
            if (self->waitResEvts[n].data.fd == self->abortFd) {
                // poll all events in abortEvt for reuse later
                EventFdClear(self->abortFd);
                self->waitResNum = nfds;
                return 0;
            }

            EvtProc *proc = (EvtProc*)self->waitResEvts[n].data.ptr;
            if (!proc) {
                LOGD("discard evt for fd removed\n");
                continue;
            }

            HI_ASSERT(proc);
            if (proc->proc) {
                // NOTE: user在事件处理时可能会删除已经产生事件的fd
                proc->proc(proc->user, proc->fd, self->waitResEvts[n].events);
            }
        }
    }
}

#else // __HuaweiLite__

int EmAddFd(EvtMon* self, int fd, int evts, EmEvtProc cb, void* user)
{
    HI_ASSERT(0);
    return -1;
}

int EmDelFd(EvtMon* self, int fd)
{
    HI_ASSERT(0);
    return -1;
}

int EmRun(EvtMon* self)
{
    HI_ASSERT(0);
    return -1;
}

#endif // __HuaweiLite__

/**
    请求终止服务.
    此函数需实现为信号安全。
*/
int EmQuit(EvtMon* self)
{
    HI_ASSERT(self);
    HI_ASSERT(self->abortFd >= 0);

    EventFdInc(self->abortFd);
    return 0;
}

/**
    EvtMon服务线程.
*/
static void* EmThrd(void* param)
{
    EvtMon* self = (EvtMon*)param;
    EmRun(self);
    return NULL;
}

/**
    启动监听服务.
*/
int EmStart(EvtMon* self)
{
    HI_ASSERT(self);
    pthread_t thrdId;

    if ((pthread_create(&thrdId, NULL, EmThrd, self)) == -1) {
        LOGE("create thread FAIL, err='%s, %d'\n", strerror(errno), errno);
        return -1;
    }
    self->svcThrdId = thrdId;
    return 0;
}

/**
    终止监听服务.
*/
int EmStop(EvtMon* self)
{
    HI_ASSERT(self);
    void *res = NULL;

    LOGI("EMON: wait svc thrd end ...\n");
    EmQuit(self);
    HI_ASSERT(self->svcThrdId > 0);
    pthread_join(self->svcThrdId, &res);
    self->svcThrdId = 0;
    LOGI("EMON: wait svc thrd end done\n");
    return 0;
}

